package com.yifang.yibingproject.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sun.deploy.services.PlatformType;
import com.yifang.yibingproject.dto.RoleDTO;
import com.yifang.yibingproject.dto.SysMenuTreeDTO;
import com.yifang.yibingproject.entity.*;
import com.yifang.yibingproject.exception.ServiceException;
import com.yifang.yibingproject.mapper.*;
import com.yifang.yibingproject.service.*;
import com.yifang.yibingproject.utils.EntityUtils;
import com.yifang.yibingproject.utils.SystemContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRoleEntity> implements SysRoleService {

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private SysRoleAuthService sysRoleAuthService;

    @Autowired
    private SysRoleAuthMapper sysRoleAuthMapper;

    @Autowired
    private SysAuthService sysAuthService;

    @Autowired
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Autowired
    private SysRoleMenuService sysRoleMenuService;

    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Autowired
    private SysMenuService sysMenuService;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysUserService sysUserService;

    /**
     * 根据ID集合获取权限集合
     * @param ids
     * @return
     */
    @Override
    public List<SysRoleEntity> getListByRoleIds(List<Long> ids) {
        if(ids == null || ids.size() == 0){
            return new ArrayList<>();
        }
        LambdaQueryWrapper<SysRoleEntity> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.in(SysRoleEntity::getId,ids);
        List<SysRoleEntity> list = list(queryWrapper);
        return list;
    }


    @Override
    public String add(String name, String description) {
        SysRoleEntity entity = EntityUtils.init(new SysRoleEntity());
        entity.setName(name);
        entity.setDescription(description);
        entity.setIsSystem(false);
        entity.setIsDisabled(false);
        save(entity);
        return String.valueOf(entity.getId());
    }

    @Override
    public String update(RoleDTO dto) {
        SysRoleEntity entity = getById(dto.getId());
        if (entity == null) {
            throw new ServiceException("角色不存在");
        }
        BeanUtils.copyProperties(dto, entity);
        EntityUtils.update(entity);
        updateById(entity);
        return String.valueOf(entity.getId());
    }

    @Transactional
    @Override
    public String del(Long id) {
        SysRoleEntity role = getById(id);
        if (role == null) {
            throw new ServiceException("角色不存在");
        }
        if (role.getIsSystem()) {
            throw new ServiceException("系统角色禁止删除");
        }
        // 检查该角色下是否有用户
        QueryWrapper<SysUserRoleEntity> wrapper = Wrappers.query();
        wrapper.eq("role_id", id);
        Integer count = sysUserRoleMapper.selectCount(wrapper);
        if (count > 0) {
            throw new ServiceException("该角色下有用户，无法删除角色");
        }

        // 更新删除角色
        UpdateWrapper<SysRoleEntity> updateWrapper = Wrappers.update();
        updateWrapper.set("is_deleted", true);
        updateWrapper.set("update_by", SystemContext.getCurrentUserId());
        updateWrapper.eq("id", id);
        update(updateWrapper);

        // 删除角色权限关联记录
        sysRoleAuthService.deleteRoleAuth(id);

        return "SUCCESS";
    }

    @Override
    public String enable(String id) {
        SysRoleEntity role = getById(id);
        if (role == null) {
            throw new ServiceException("角色不存在");
        }
        if (!role.getIsDisabled()) {
            throw new ServiceException("角色已启用");
        }
        role.setIsDisabled(false);
        role.setUpdateBy(SystemContext.getCurrentUserId());
        updateById(role);
        return id;
    }

    @Override
    public String disable(String id) {
        SysRoleEntity role = getById(id);
        if (role == null) {
            throw new ServiceException("角色不存在");
        }
        if (role.getIsDisabled()) {
            throw new ServiceException("角色已禁用");
        }
        role.setIsDisabled(true);
        role.setUpdateBy(SystemContext.getCurrentUserId());
        updateById(role);
        return id;
    }

    @Override
    public String bindAuth(Long roleId, Set<Long> authIds) {
        SysRoleEntity role = getById(roleId);
        if (role == null) {
            throw new ServiceException("角色不存在");
        }

        if (role.getIsDisabled()) {
            throw new ServiceException("角色已禁用，无法绑定权限");
        }

        Set<Long> authIdSet = sysAuthService.getAllAuthIdSet();
        if (authIdSet.containsAll(authIds)) {
            for (Long authId : authIds) {
                SysRoleAuthEntity roleAuth = EntityUtils.init(new SysRoleAuthEntity());
                roleAuth.setRoleId(roleId);
                roleAuth.setAuthId(authId);
                sysRoleAuthMapper.insert(roleAuth);
            }
        } else {
            throw new ServiceException("禁止绑定未知权限");
        }
        return "SUCCESS";
    }

    /**
     * 给角色绑定权限
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public Page<RoleDTO> list(int pageNo, int pageSize) {
        Page<SysRoleEntity> page = new Page<>(pageNo, pageSize);
        QueryWrapper wrapper = Wrappers.query();
        page = page(page, wrapper);
        Page<RoleDTO> dtoPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        List<SysRoleEntity> records = page.getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            List<Long> roleIds=records.stream().map(SysRoleEntity::getId).distinct().collect(Collectors.toList());
            List<SysUserRoleEntity> sysUserRoleEntities = sysUserRoleService.safetyGetListByRoleIds(roleIds);
            Map<Long,List<SysUserRoleEntity>> sysUserRoleMap = sysUserRoleEntities.stream().collect(Collectors.groupingBy(SysUserRoleEntity::getRoleId));

            //获取用户
            List<Long> userIds = sysUserRoleEntities.stream().map(SysUserRoleEntity::getUserId).collect(Collectors.toList());
            List<SysUserEntity> userList = sysUserService.safetyGetListByIds(userIds);
            Map<Long,SysUserEntity> userMap = userList.stream().collect(Collectors.toMap(SysUserEntity::getId, Function.identity()));

            List<RoleDTO> dtoList = new ArrayList<>();
            for (SysRoleEntity role : page.getRecords()) {
                RoleDTO dto = new RoleDTO();
                BeanUtils.copyProperties(role, dto);
                AtomicInteger membersCount= new AtomicInteger(0);

                Optional.ofNullable(sysUserRoleMap.get(role.getId())).orElse(new ArrayList<>()).stream().forEach(item -> {
                    if(userMap.get(item.getUserId()) != null){
                        membersCount.incrementAndGet();
                    }
                });

                dto.setMembersCount(membersCount.intValue());
                dtoList.add(dto);
            }
            dtoPage.setRecords(dtoList);
        }
        return dtoPage;
    }

    @Override
    public List<RoleDTO> listAll() {
        QueryWrapper<SysRoleEntity> wrapper = Wrappers.query();
        wrapper.orderByAsc("create_time");
        List<SysRoleEntity> entityList = list(wrapper);
        List<RoleDTO> dtoList = new ArrayList<>();
        for (SysRoleEntity entity : entityList) {
            RoleDTO dto = new RoleDTO();
            BeanUtils.copyProperties(entity, dto);
            dtoList.add(dto);
        }
        return dtoList;
    }

    @Override
    @Transactional
    public String bindMenu(Long roleId, Set<Long> menuIds) {
        SysRoleEntity role = getById(roleId);
        if (role == null) {
            throw new ServiceException("角色不存在");
        }

        if (role.getIsDisabled()) {
            throw new ServiceException("角色已禁用，无法绑定菜单");
        }

        Set<Long> menuIdSet = sysMenuService.getAllMenuIdSet();
        if (menuIdSet.containsAll(menuIds)) {

            Set<Long> myMenuIdSet = sysRoleMenuService.getMenuIdByRoleId(roleId);
            for (Long menuId : menuIds) {

                if(myMenuIdSet.contains(menuId)){
                    continue;
                }

                SysRoleMenuEntity entity = EntityUtils.init(new SysRoleMenuEntity());
                entity.setRoleId(roleId);
                entity.setMenuId(menuId);
                sysRoleMenuService.save(entity);
            }

            //取消菜单
            Optional.ofNullable(myMenuIdSet.stream().filter(item->!menuIds.contains(item)).collect(Collectors.toSet())).ifPresent(
                deleted->{
                    if (deleted.isEmpty()){
                        return;
                    }
                    LambdaUpdateWrapper<SysRoleMenuEntity> deleteWrapper = new LambdaUpdateWrapper<>();
                    deleteWrapper.in(SysRoleMenuEntity::getMenuId,deleted);
                    deleteWrapper.eq(SysRoleMenuEntity::getRoleId,roleId);
                    sysRoleMenuService.remove(deleteWrapper);
                }
            );


        } else {
            throw new ServiceException("禁止绑定未知菜单");
        }

        return "SUCCESS";
    }

    @Override
    public List<SysMenuTreeDTO> menuTree(Long id) {
        List<SysMenuTreeDTO> dtoList = new ArrayList<>();

        Set<Long> menuIdSet = sysRoleMenuService.getMenuIdByRoleId(id);
        if (menuIdSet.size() == 0) {
            return dtoList;
        }

        List<SysMenuEntity> list = sysMenuMapper.selectBatchIds(menuIdSet);

        if (!list.isEmpty()) {
            List<SysMenuEntity> subList = list.stream().filter(cate -> "root".equals(cate.getParentId())).collect(Collectors.toList());
            if (!subList.isEmpty()) {
                list.removeAll(subList);
                for (SysMenuEntity root : subList) {
                    SysMenuTreeDTO dto = new SysMenuTreeDTO();
                    BeanUtils.copyProperties(root, dto);
                    dtoList.add(dto);
                    setChildren(dto, list);
                }
            }
        }
        //直接在这里添加我们的排序规则
        Collections.sort(dtoList, new Comparator<SysMenuTreeDTO>() {
            public int compare(SysMenuTreeDTO arg0, SysMenuTreeDTO arg1) {
                return arg0.getSortIndex().compareTo(arg1.getSortIndex());
            }
        });
        return dtoList;
    }

    @Override
    public RoleDTO get(String id) {
        SysRoleEntity entity = getById(id);
        RoleDTO dto = new RoleDTO();
        BeanUtils.copyProperties(entity, dto);
        return dto;
    }

    /**
     * 根据用户ID获取用户角色名称集合
     * @param userId
     * @return
     */
    @Override
    public List<String> getRoleNameByUserId(Long userId) {
        if(userId == null || userId <= 0){
            return new ArrayList<>();
        }
        List<SysRoleEntity> list = sysUserRoleService.listRolesByUserId(userId);
        List<String> result = list.stream().map(SysRoleEntity::getName).collect(Collectors.toList());
        return result;
    }

    private void setChildren(SysMenuTreeDTO parent, List<SysMenuEntity> list) {
        List<SysMenuTreeDTO> dtoList = new ArrayList<>();
        parent.setChildren(dtoList);
        List<SysMenuEntity> subList = list.stream().filter(cate -> parent.getId().equals(cate.getParentId())).collect(Collectors.toList());
        if (!subList.isEmpty()) {
            list.removeAll(subList);
            for (SysMenuEntity entity : subList) {
                SysMenuTreeDTO dto = new SysMenuTreeDTO();
                BeanUtils.copyProperties(entity, dto);
                dtoList.add(dto);
                //直接在这里添加我们的排序规则
                Collections.sort(dtoList, new Comparator<SysMenuTreeDTO>() {
                    public int compare(SysMenuTreeDTO arg0, SysMenuTreeDTO arg1) {
                        return arg0.getSortIndex().compareTo(arg1.getSortIndex());
                    }
                });
                setChildren(dto, list);
            }
        }
    }

    private void checkNameRepeat(PlatformType type, String name) {
        QueryWrapper<SysRoleEntity> wrapper = Wrappers.query();
        wrapper.eq("name", name);
        wrapper.last("limit 1");
        SysRoleEntity one = getOne(wrapper);
        if (one != null && one.getName().equals(name)) {
            throw new ServiceException("角色名称已存在");
        }
    }
}
